/**
 *******************************************************************************
 * \brief   CAS EBX Project Work "Kaffeemaschine"
 *
 * \file    ui.c
 * \version 1.0
 * \date    30.06.2010
 * \author  Baehler Thomas, Liechti Beat, Sauter Marc
 * \author  Vuksic Valentina, Zbinden Rene
 *
 * \remark  Last Modifications:
 * \remark  V1.0, 30.06.2010   Initial release
 *******************************************************************************
 **/

/*
 *******************************************************************************
 * Definitions
 *******************************************************************************
 */


/*
 *******************************************************************************
 * Imports
 *******************************************************************************
 */
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <syslog.h>
#include <unistd.h>

#include "coffee2.h"
#include "channel.h"
#include "pool.h"
#include "device.h"

/*
 *******************************************************************************
 * Local Variables
 *******************************************************************************
 */
static tChannel *c4, /**c6r, *c6w, *c7,*/ *c9, *c10, *c35;
static tPool *p1, *p2, *p3;
static tDevice *d6, *d7;
static int timeExpired = 0;

/*
 *******************************************************************************
 * Local Function Declaration
 *******************************************************************************
 */
static void sigtermHandler(int signal);
static void setTimeExpired(int signal);
static void updateDisplay(int val);

/**
 *******************************************************************************
 * sigtermHandler
 *
 * \brief handle SIGTERM signal, close all pools and channels and exit
 *
 * \return status
 *
 *******************************************************************************
 **/
static void sigtermHandler(int signal) {
	syslog(LOG_INFO, "SIGTERM reveiced, stopping ...");
	/* close channels and pools */
	closeChannel(c4);
	//closeChannel(c6r);
	//closeChannel(c6w);
	closeDevice(d6);
	//closeChannel(c7);
	closeDevice(d7);
	closeChannel(c9);
	closeChannel(c10);
	closeChannel(c35);
	closePool(p1);
	closePool(p2);
	closePool(p3);
	/* close syslog */
	closelog();
	/* close and remove the runfile */
	exit(EXIT_SUCCESS);
}


/**
 *******************************************************************************
 * setTimeExpired
 *
 * \brief handle SIGALRM signal, set timeExpired
 *
 * \return void
 *
 *******************************************************************************
 **/
static void setTimeExpired(int signal) {
	timeExpired = 1;
	return;
}


/**
 *******************************************************************************
 * updateDisplay
 *
 * \brief update the display, write to the channel
 *
 * \param data data structure to write
 *
 * \return void
 *
 *******************************************************************************
 **/
static void updateDisplay(int val) {
	writeDevice(d6, val);
	//int oldData;
	 /* ensure that the channel don't get filled */
	//readChannel(c6r, &oldData);
	/* write new message */
	//writeChannel(c6w, data);
	return;
}


/**
 *******************************************************************************
 * updateStatistic
 *
 * \brief update the statistic pool
 *
 * \param data data structure to write
 *
 * \return
 *
 *******************************************************************************
 **/
static void updateStatistic(void *data) {
	int count;
	/* for this prototyp, simple increment a counter */
	readFromPool(p1, &count);
	count++;
	writeToPool(p1, &count);
	return;
}


/**
 *******************************************************************************
 * mainUi
 *
 * \brief Aktivität: "User Interface"
 *
 * \return pid
 *
 *******************************************************************************
 **/
pid_t mainUi(){
	pid_t pid;
	sigset_t sigmask;
	struct sigaction sigtermAction;
	enum e_states button = OFF;
	enum e_errors error = NO_ERROR;
	int statistic = 0;
	int parameter = 0;
	int standby = 0;

	pid = fork();
	if (pid == 0) {
		/* syslog */
		closelog();
		openlog("coffee-ui", LOG_PID, LOG_DAEMON);
		/* block all signals other than SIGTERM */
		sigemptyset(&sigmask);
		sigaddset(&sigmask, SIGTERM);
		sigtermAction.sa_handler = sigtermHandler;
		sigtermAction.sa_mask = sigmask;
		if (sigaction(SIGTERM, &sigtermAction, NULL) == -1){
			syslog(LOG_ERR, "unable to setup signal handling!");
		}
		/* register alarm function */
		if (signal(SIGALRM, setTimeExpired) == SIG_ERR) {
			syslog(LOG_ERR, "can't register SIGALRM!");
		}

		/* open devices, channels and pools */
		c4 = openChannelWrite("C4", sizeof(int));   /* write to
		                                                     "Programmierung" */
		//c6r = openChannelRead("C6", sizeof(int));   /* read from "Display" */
		//c6w = openChannelWrite("C6", sizeof(int));  /* write to "Display" */
		d6 = openDeviceWrite("/dev/c2display");		/* write to "Display" */
		//c7 = openChannelRead("C7", sizeof(int));    /* read from "Knoepfe" */
		d7 = openDeviceRead("/dev/c2buttons");
		c9 = openChannelWrite("C9", sizeof(int));   /* write to "Statistik" */
		c10 = openChannelWrite("C10", sizeof(int)); /* write to "Tasse" */
		c35 = openChannelRead("C35", sizeof(int));  /* read from "Status" */
		p1 = openPool("P1", sizeof(statistic));     /* "Statstik" */
		p2 = openPool("P2", sizeof(parameter));     /* "Parameter" */
		p3 = openPool("P3", sizeof(error));         /* "Error" */

		while (1) {
			readFromPool(p3, &error);
			if (error != NO_ERROR) {
				syslog(LOG_INFO, "entering error state");
			}
			while (error != NO_ERROR) {
				updateDisplay(error);
				usleep(500);
				readFromPool(p3, &error);
				if (error == NO_ERROR) {
					syslog(LOG_INFO, "leaving error state" );
				}
			}
			/* evaluate button */
			//if (readChannel(c7, &button) > 0) {
			int btn;
			if (readDevice(d7, &btn) == sizeof(btn) && btn >= 0) {
				button = btn;
				syslog(LOG_INFO, "button %d pressed", button);
				if (button == OFF) {
					syslog(LOG_INFO, "entering standby mode");
					updateDisplay(button);
					standby = 1;
				} else if (button == READY) {
					/* ignore, machine is still running */
					;
				} else if (button < STATISTIK) {
					updateDisplay(button);
					syslog(LOG_INFO, "sending order to C10");
					writeChannel(c10, &button);
					timeExpired = 0;
					alarm(PRODUCTION_TIMEOUT);
					syslog(LOG_INFO, "waiting for completion message");
					while (readChannel(c35, &button) == 0 && timeExpired == 0
														 && error == NO_ERROR) {
						readFromPool(p3, &error);
						usleep(500);
					}
					if (timeExpired == 1) {
						syslog(LOG_ERR, "did not receive completion message");
						error = NO_COMPLETION;
						writeToPool(p3, &error);
					} else if (error != NO_ERROR) {
						syslog(LOG_ERR, "error occured");
						updateDisplay(error);
						/*
						 * if there was no cup,
						 * wait a jiffy and reset the error automatically
						 */
						if (error == NO_CUP) {
							syslog(LOG_INFO, "there was no cup");
							error = NO_ERROR;
							writeToPool(p3, &error);
							sleep(2);
						}
					} else {
						syslog(LOG_INFO, "completion message received");
						updateStatistic(NULL);
					}
					alarm(0);
				} else if (button == STATISTIK) {
					updateDisplay(button);
					writeChannel(c9, &button);
				} else {
					updateDisplay(button);
					writeChannel(c4, &button);
				}
			}
			/* standy mode */
			while (standby == 1) {
				//if (readChannel(c7, &button) > 0) {
				if (readDevice(d7, &btn) > 0 && btn >= 0) {
					button = btn;
					if (button == OFF) {
						syslog(LOG_INFO, "initiating shutdown sequence");
						kill(getppid(), SIGTERM);
					} else if (button == READY) {
						syslog(LOG_INFO, "leaving standby mode");
						standby = 0;
					}
				}
				usleep(1000);
			}
			usleep(500);
		}
	}
	return pid;
}
